package cn.yangphere.service.base;

import java.util.LinkedHashMap;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import cn.yangphere.bean.AnnotationUtils;
import cn.yangphere.bean.QueryResult;

@Transactional
public abstract class DaoSupport implements Dao {

	@PersistenceContext
	protected EntityManager em;

	@Override
	public void save(Object entity) {
		em.persist(entity);
	}

	@Override
	public void update(Object entity) {
		em.merge(entity);
	}

	@Override
	public <T> void delete(Class<T> entityClass, Object entityId) {
		delete(entityClass, new Object[] { entityId });
	}

	@Override
	public <T> void delete(Class<T> entityClass, Object[] entityIds) {
		for (Object id : entityIds) {
			em.remove(em.getReference(entityClass, id));
		}
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	public <T> T find(Class<T> entityClass, Object entityId) {
		return em.find(entityClass, entityId);
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	public <T> QueryResult<T> getScrollData(Class<T> entityClass,
			int firstIndex, int maxResult, String whereJpql,
			Object[] queryParams, LinkedHashMap<String, String> orderBy) {
		QueryResult<T> qr = new QueryResult<T>();

		String entityName = AnnotationUtils.getEntityName(entityClass);

		Query query = em.createQuery("select o from " + entityName + " o "
				+ (whereJpql == null ? "" : " where " + whereJpql)
				+ buildOrderBy(orderBy));
		setQueryParams(query, queryParams);

		if (firstIndex != -1 && maxResult != -1) {
			query.setFirstResult(firstIndex).setMaxResults(maxResult);
		}

		qr.setResultList(query.getResultList());
		query = em.createQuery("select count(o) from " + entityName + " o "
				+ (whereJpql == null ? "" : " where " + whereJpql));
		setQueryParams(query, queryParams);
		qr.setTotalRecord((Long) query.getSingleResult());
		return qr;
	}

	protected void setQueryParams(Query query, Object[] queryParams) {
		if (queryParams != null && queryParams.length > 0) {
			for (int i = 0; i < queryParams.length; i++) {
				query.setParameter(i + 1, queryParams[i]);
			}
		}
	}

	/**
	 * 组装order by 语句
	 * 
	 * @param orderBy
	 * @return
	 */
	protected String buildOrderBy(LinkedHashMap<String, String> orderBy) {
		StringBuffer orderByQl = new StringBuffer();
		if (orderBy != null && orderBy.size() > 0) {
			orderByQl.append(" order by ");
			for (String key : orderBy.keySet()) {
				orderByQl.append("o.").append(key).append(" ")
						.append(orderBy.get(key)).append(",");
			}
			orderByQl.deleteCharAt(orderByQl.length() - 1);
		}
		return orderByQl.toString();
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	public <T> QueryResult<T> getScrollData(Class<T> entityClass,
			int firstIndex, int maxResult, String whereJpql,
			Object[] queryParams) {
		return getScrollData(entityClass, firstIndex, maxResult, whereJpql,
				queryParams, null);
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	public <T> QueryResult<T> getScrollData(Class<T> entityClass,
			int firstIndex, int maxResult, LinkedHashMap<String, String> orderBy) {
		return getScrollData(entityClass, firstIndex, maxResult, null, null,
				orderBy);
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	public <T> QueryResult<T> getScrollData(Class<T> entityClass,
			int firstIndex, int maxResult) {
		return getScrollData(entityClass, firstIndex, maxResult, null);
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
	public <T> QueryResult<T> getScrollData(Class<T> entityClass) {
		return getScrollData(entityClass, -1, -1);
	}

}
